using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Diagnostics;
using TrenchcoatRobots.Classes;
using TrenchcoatRobots.Classes.ComponentClasses;
using TrenchcoatRobots.Classes.ComponentClasses.UI;
using TrenchcoatRobots.Classes.ComponentClasses.Colliders;
using TrenchcoatRobots.Datatypes;
using TrenchcoatRobots.Datatypes.States;
using TrenchcoatRobots.Datatypes.Input;

namespace TrenchcoatRobots {
	public class Trobots : Microsoft.Xna.Framework.Game {
		GraphicsDeviceManager graphics;
		SpriteBatch spriteBatch;
		List<Layer> layers = new List<Layer>();
		RenderTarget2D sceneTarget;
		Texture2D sceneTex;
		Model screenMesh;
        Texture2D spriteSheet;

		public Trobots() {
			graphics = new GraphicsDeviceManager(this);
			Content.RootDirectory = "Content";
			IsFixedTimeStep = false;
			ClientSettings.ScreenWidth = 1200;
			ClientSettings.ScreenHeight = 600;
			ClientSettings.windowState = WindowState.Windowed;
			ClientSettings.UseVsync = false;
			ClientSettings.MultiSampling = false;
		}

		protected override void Initialize() {
			this.IsFixedTimeStep = false;

			#region P1
			GameState.FirstPlayerInputs = new List<Datatypes.Input.GameInput>();
			GameState.FirstPlayerInputs.Add(new KeyboardInput(Keys.D, Keys.A, "horizontal"));
			GameState.FirstPlayerInputs.Add(new KeyboardInput(Keys.Right, Keys.Left, "horizontal"));
			GameState.FirstPlayerInputs.Add(new KeyboardInput(Keys.S, Keys.W, "vertical"));
			GameState.FirstPlayerInputs.Add(new KeyboardInput(Keys.Down, Keys.Up, "vertical"));
			GameState.FirstPlayerInputs.Add(new KeyboardInput(Keys.Space, "jump"));
			#endregion
			#region P2
			GameState.SecondPlayerInputs = new List<Datatypes.Input.GameInput>();

			#endregion

			PhysicsState.Gravity = new Vector2(0, 9.82f);

			base.Initialize();
		}

		protected override void LoadContent() {
			graphics.PreferredBackBufferWidth = ClientSettings.ScreenWidth;
			graphics.PreferredBackBufferHeight = ClientSettings.ScreenHeight;
			graphics.PreferMultiSampling = ClientSettings.MultiSampling;
			graphics.SynchronizeWithVerticalRetrace = ClientSettings.UseVsync;
			if (ClientSettings.windowState == WindowState.Fullscreen) {
				graphics.IsFullScreen = true;
			}
			else {
				graphics.IsFullScreen = false;
			}
			graphics.ApplyChanges();

			sceneTarget = new RenderTarget2D(GraphicsDevice, ClientSettings.ScreenWidth / 2, ClientSettings.ScreenHeight / 2);
			screenMesh = Content.Load<Model>("ScreenMesh");
            spriteSheet = Content.Load<Texture2D>("spriteSheet");

			spriteBatch = new SpriteBatch(GraphicsDevice);
			layers.Add(new Layer(0, new DrawInfo(new Camera(), graphics)));
			layers.Add(new Layer(0, new DrawInfo(new Camera(), graphics)));

			GameObject textFXtest = new GameObject(new Vector2(ClientSettings.ScreenWidth * 0.25f, 80));
			TextEffect tEffect = new TextEffect(textFXtest.ReturnSelf, Content.Load<SpriteFont>("effectFont"));
			textFXtest.AddComponent(tEffect);
			layers[1].GameObjects.Add(textFXtest);

			#region create player animations
			List<Rectangle> idleFrames = new List<Rectangle>();
			idleFrames.Add(new Rectangle(0, 0, 24, 32));
			Animation idle = new Animation(idleFrames, 15, AnimationPlayback.Loop);

			List<Rectangle> walkFrames = new List<Rectangle>();
			walkFrames.Add(new Rectangle(24,0,24,32));
			walkFrames.Add(new Rectangle(48,0,24,32));
			Animation walk = new Animation(walkFrames, 15, AnimationPlayback.Loop);

			List<Rectangle> jumpFrames = new List<Rectangle>();
			jumpFrames.Add(new Rectangle(72, 0, 24, 32));
			Animation jump = new Animation(jumpFrames, 15, AnimationPlayback.Loop);
			#endregion

			GameObject player = new GameObject(new Vector2(40, 250));
			BoxCollider bCol = new BoxCollider(player.ReturnSelf, new Vector2(), new Vector2(24, 32));
			PlayerControl pCon = new PlayerControl(player.ReturnSelf, 300, 0.05f, .74f, 0.99f, 100, Classes.ComponentClasses.PlayerNumber.First); // playercontrol debug
			AnimatedTextureRenderer aCon = new AnimatedTextureRenderer(player.ReturnSelf, spriteSheet, "idle", idle); // playercontrol debug
			aCon.RendererAnimations.Add("walk", walk);
			aCon.RendererAnimations.Add("jump", jump);
			pCon.teffect = textFXtest;
			player.AddComponent(bCol);
			player.AddComponent(pCon); //playercontrol debug
			player.AddComponent(aCon); //playercontrol debug


			layers[0].GameObjects.Add(player);

			#region Groundplane
			GameObject ground = new GameObject(new Vector2(0, ClientSettings.ScreenHeight - 300), "ground");
			BoxCollider gCol = new BoxCollider(ground.ReturnSelf, new Vector2(), new Vector2(ClientSettings.ScreenWidth, 100));
			BoxObject groundBox = new BoxObject(ground.ReturnSelf, new Vector2(), new Vector2(ClientSettings.ScreenWidth, 100), Color.Blue);
			ground.AddComponent(gCol);
			ground.AddComponent(groundBox);
			layers[0].GameObjects.Add(ground);
			#endregion

			GameObject progressbarTest = new GameObject(new Vector2(50, 50));
			ProgressBar pbar = new ProgressBar(progressbarTest.ReturnSelf, Content.Load<Texture2D>("pbarTest"));
			pbar.UVmultiplier = 32;
			pbar.Reverse = true;
			progressbarTest.AddComponent(pbar);
			layers[1].GameObjects.Add(progressbarTest);
		}

		protected override void UnloadContent() {

		}

		protected override void Update(GameTime gameTime) {
			// Update inputs
			UpdateInputs();

			#region Update Layers
			foreach (Layer lajor in layers) {
				if (lajor.Active) {
					foreach (GameObject gajm in lajor.GameObjects) {
						if (gajm.Active) {
							gajm.Update(ref gameTime);
							for (int i = 0; i < lajor.GameObjects.Count; i++) {
								if (lajor.GameObjects[i].Active && lajor.GameObjects[i] != gajm) {
									ColliderManager.CollideObjects((BoxCollider)gajm.GetComponent<BoxCollider>(), (BoxCollider)lajor.GameObjects[i].GetComponent<BoxCollider>());
								}
							}
						}
					}
				}
				for (int i = lajor.GameObjects.Count - 1; i > -1; i--) {
					if (lajor.GameObjects[i].Destroy) {
						lajor.GameObjects.RemoveAt(i);
					}
				}
			}
			#endregion

			base.Update(gameTime);
		}

		protected override void Draw(GameTime gameTime) {

			GraphicsDevice.SetRenderTarget(sceneTarget);
			GraphicsDevice.Clear(Color.Aquamarine);

			spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointWrap, null, null);
			foreach (Layer l in layers) {
				if (l.Visible) {
					foreach (GameObject g in l.GameObjects) {
						g.Draw(ref spriteBatch, l.DrawInfo);
					}
				}
			}
			spriteBatch.End();

			sceneTex = (Texture2D)sceneTarget;

			GraphicsDevice.SetRenderTarget(null);

			GraphicsDevice.Clear(Color.Black);

			Matrix[] transforms = new Matrix[screenMesh.Bones.Count];
			screenMesh.CopyAbsoluteBoneTransformsTo(transforms);

			graphics.GraphicsDevice.SamplerStates[0] = SamplerState.PointClamp;

			foreach (ModelMesh mesh in screenMesh.Meshes) {
				foreach (BasicEffect effect in mesh.Effects) {
					effect.Texture = sceneTex;
					effect.TextureEnabled = true;
					effect.LightingEnabled = false;
					effect.World = transforms[mesh.ParentBone.Index] * Matrix.CreateRotationX(MathHelper.ToRadians(-90));
					effect.View = Matrix.CreateLookAt(new Vector3(1, 0, 0), Vector3.Zero, Vector3.Up);
					effect.Projection = Matrix.CreateOrthographic((float)ClientSettings.ScreenWidth / (float)ClientSettings.ScreenHeight, 1, 0.001f, 1000);
				}
				mesh.Draw();
			}

			base.Draw(gameTime);
		}

		protected void UpdateInputs() {
			KeyboardState ks = Keyboard.GetState();
			MouseState ms = Mouse.GetState();
			GamePadState gps1 = GamePad.GetState(PlayerIndex.One);
			GamePadState gps2 = GamePad.GetState(PlayerIndex.Two);

			UpdateInputList(GameState.FirstPlayerInputs, ks);
			UpdateInputList(GameState.SecondPlayerInputs, ks);
		}

		protected void UpdateInputList(List<GameInput> list, KeyboardState ks) {
			for (int i = 0; i < list.Count; i++) {
				list[i].Update(ref ks);
			}
		}

		void Window_ClientSizeChanged(object sender, EventArgs e) {
			ClientSettings.ScreenWidth = Window.ClientBounds.Width;
			ClientSettings.ScreenHeight = Window.ClientBounds.Height;
		}
	}
}
